package com.base.utils

import org.springframework.util.Base64Utils
import java.security.Key
import java.security.spec.AlgorithmParameterSpec
import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.DESKeySpec
import javax.crypto.spec.IvParameterSpec

class DES {
    var padding = PADDING
        private set
    var initializationVectorBytes = DEFAULT_INITIALIZATION_VECTOR
        private set
    private var paramSpec: AlgorithmParameterSpec

    constructor() {
        paramSpec = IvParameterSpec(initializationVectorBytes)
    }

    constructor(padding: String) {
        this.padding = padding
        paramSpec = IvParameterSpec(initializationVectorBytes)
    }

    constructor(padding: String, initializationVectorBytes: ByteArray) {
        this.padding = padding
        this.initializationVectorBytes = initializationVectorBytes
        paramSpec = IvParameterSpec(initializationVectorBytes)
    }

    constructor(initializationVectorBytes: ByteArray) {
        this.initializationVectorBytes = initializationVectorBytes
        paramSpec = IvParameterSpec(initializationVectorBytes)
    }

    @Throws(Exception::class)
    fun encodeBytes(data: ByteArray?, key: ByteArray): ByteArray {
        val secretKey: Key = getKey(key)
        val cipher = Cipher.getInstance(padding)
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec)
        return cipher.doFinal(data)
    }

    @Throws(Exception::class)
    fun decodeBytes(data: ByteArray?, key: ByteArray): ByteArray {
        val secretKey: Key = getKey(key)
        val cipher = Cipher.getInstance(padding)
        cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec)
        return cipher.doFinal(data)
    }

    companion object {
        const val ALGORITHM = "DES"
        const val PADDING = "DES/CBC/PKCS5Padding"
        private val DEFAULT_INITIALIZATION_VECTOR = "00000000".toByteArray()

        @Throws(Exception::class)
        fun main(res: String, appSecret: String) {
            val decode = decode(Base64Utils.decode(res.toByteArray()), appSecret.toByteArray())
            val result = String(decode)
        }

        @Throws(Exception::class)
        private fun getKey(key: ByteArray): Key {
            val dks = DESKeySpec(key)
            val keyFactory = SecretKeyFactory.getInstance(ALGORITHM)
            return keyFactory.generateSecret(dks)
        }

        @JvmOverloads
        @Throws(Exception::class)
        fun decode(data: ByteArray?, key: ByteArray, ivBytes: ByteArray = DEFAULT_INITIALIZATION_VECTOR): ByteArray {
            val des = DES(PADDING, ivBytes)
            return des.decodeBytes(data, key)
        }

        @JvmOverloads
        @Throws(Exception::class)
        fun encode(data: ByteArray?, key: ByteArray, ivBytes: ByteArray = DEFAULT_INITIALIZATION_VECTOR): ByteArray {
            val des = DES(PADDING, ivBytes)
            return des.encodeBytes(data, key)
        }
    }
}
